#ifndef __CGE_MATRIX4__
#define __CGE_MATRIX4__

#include "cgeCommons.h"

namespace cge
{
	namespace std
	{
		template<class TVal, u32 NRows, u32 NCols>
		class Matrix;

		template<class TVal>
		class Matrix<TVal, 4, 4>
		{
		public:
			Matrix()
			{
				LoadZero();
			}

			Matrix(TVal m00, TVal m01, TVal m02, TVal m03, 
				   TVal m10, TVal m11, TVal m12, TVal m13, 
				   TVal m20, TVal m21, TVal m22, TVal m23, 
				   TVal m30, TVal m31, TVal m32, TVal m33)
			{
				Set(m00, m01, m02, m03, m10, m11, m12, m13, 
					m20, m21, m22, m23, m30, m31, m32, m33);
			}

			Matrix(const TVal* arr, u32 count = 16, u32 start = 0)
			{
				LoadZero();
				Set(arr, count, start);
			}

			void LoadZero()
			{
				M00 = M01 = M02 = M03 =
				M10 = M11 = M12 = M13 =
				M20 = M21 = M22 = M23 =
				M30 = M31 = M32 = M33 = (TVal)0;
			}

			void LoadIdentity()
			{
				M00 = M11 = M22 = M33 = (TVal) 1;
				M01 = M02 = M03 =
				M10 = M12 = M13 =
				M20 = M21 = M23 =
				M30 = M31 = M32 = (TVal) 0;
			}

			void Set(TVal m00, TVal m01, TVal m02, TVal m03, 
					 TVal m10, TVal m11, TVal m12, TVal m13, 
					 TVal m20, TVal m21, TVal m22, TVal m23, 
					 TVal m30, TVal m31, TVal m32, TVal m33)
			{
				M00 = m00; M01 = m01; M02 = m02; M03 = m03;
				M10 = m10; M11 = m11; M12 = m12; M13 = m13;
				M20 = m20; M21 = m21; M22 = m22; M23 = m23;
				M30 = m30; M31 = m31; M32 = m32; M33 = m33;
			}

			void Set(const TVal* arr, u32 count = 16, u32 start = 0)
			{
				for(u32; i < 16 && i < count; i++)
					A1D[i] = arr[start + i];
			}

			Matrix Transpose() const
			{
				return Matrix(M00, M10, M20, M30,
							  M01, M11, M21, M31,
							  M02, M12, M22, M32,
							  M03, M13, M23, M33);
			}

		public:
			union
			{
				struct
				{
					TVal M00, M01, M02, M03,
						 M10, M11, M12, M13,
						 M20, M21, M22, M23,
						 M30, M31, M32, M33;
				};
				TVal A2D[4][4]; //as 2-dimensional array
				TVal A1D[16];	//as 1-dimensional array
			};
		};

		typedef Matrix<f32, 4, 4> Matrix4f;

		typedef Matrix<f64, 4, 4> Matrix4d;
	}
}

#endif//__CGE_MATRIX4__